home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr22
/
ctest259.zip
/
DHRY.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1992-04-05
|
28KB
|
764 lines
{$A+,B-,D-,E+,F-,G-,I-,L-,N+,O-,R-,S-,V-,X-}
{$M 4096,0,655360}
UNIT Dhry;
INTERFACE
FUNCTION Dhrystones (Index: DOUBLE): DOUBLE;
IMPLEMENTATION
USES Time;
(*
****************************************************************************
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: Pascal, Version 2.1
*
* File: dhry.p
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
* Siemens AG, E STE 35
* Postfach 3220
* 8520 Erlangen
* Germany (West)
* Phone: [xxx-49]-9131-7-20330
* (8-17 Central European Time)
* Usenet: ..!mcvax!unido!estevax!weicker
*
* Original Version (in Ada) published in
* "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
* pp. 1013 - 1030, together with the statistics
* on which the distribution of statements etc. is based,
*
* This version uses calls to the Pascal runtime library of the
* Berkeley UNIX system (4.3 bsd) for time measurement.
* For measurements on other systems, these calls need to be
* modified.
*
* Collection of Results:
* Reinhold Weicker (address see above) and
*
* Rick Richardson
* PC Research. Inc.
* 94 Apple Orchard Drive
* Tinton Falls, NJ 07724
* Phone: (201) 834-1378 (9-17 EST)
* Usenet: ...!seismo!uunet!pcrat!rick
*
* Please send results to Rick Richardson and/or Reinhold Weicker.
* Complete information should be given on hardware and software used.
* Hardware information includes: Machine type, CPU, type and size
* of caches; for microprocessors: clock frequency, memory speed
* (number of wait states).
* Software information includes: Compiler (and runtime library)
* manufacturer and version, compilation switches, OS version.
* The Operating System version may give an indication about the
* compiler; Dhrystone itself performs no OS calls in the measurement loop.
*
* The complete output generated by the program should be mailed
* such that at least some checks for correctness can be made.
*
****************************************************************************
*
* History: This version Pascal/2.1 has been made for two reasons:
*
* 1) There is a need for a common Pascal version of
* Dhrystone. Although translation from the published (Ada)
* version to Pascal is straightforward in most aspects,
* there are cases where it may not be obvious to everyone.
* There should be, as far as possible, only one Pascal version
* of Dhrystone such that results can be compared without
* restrictions. Also, a Pascal version of Dhrystone has not yet
* found a network distribution comparable to the C version
* (version 1.1) distributed by Rick Richardson.
*
* 2) As far as it is possible without changes to the Dhrystone
* statistics, optimizing compilers should be prevented from
* removing significant statements.
*
* This Pascal version 2.1 has been made consistent with the
* C version 2.1; therefore the acknowledgments for the C version
* are due for the Pascal version as well: I thank
* Rick Richardson (Tinton Falls, NJ), Chaim Benedelac (Nat.
* Semi.), David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
* Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
* for their help with comments on earlier versions of the
* benchmark.
*
* Changes: In the initialization part, this version differs
* from the Pascal version previously distributed by Reinhold
* Weicker, the number of runs through Dhrystone is obtained
* interactively from the terminal. Output of the result
* has been changed to conform to the C version (2.1).
* The changes in the initialization part and in the printing
* of the result have no impact on performance measurement
* since they are outside the measaurement loop.
*
* Inside the measurement loop, this version follows the
* version previously distributed by Reinhold Weicker.
* As a correction to the published version, a statement
* initializing Array2Glob [8,7] (outside the measurement
* loop) has been added. Otherwise, this array element would
* have an undefined value.
*
* At several places in the benchmark, code has been added,
* but within the measurement loop only in branches that
* are not executed. The intention is that optimizing compilers
* should be prevented from moving code out of the measurement
* loop, or from removing code altogether. Since the statements
* that are executed within the measurement loop have NOT been
* changed, all numbers defining the "Dhrystone distribution"
* (distribution of statements, operand types and locality)
* still hold. Except for sophisticated optimizing compilers,
* execution times for this version should be the same as
* for previous versions.
*
* Since it has proven difficult to subtract the time for the
* measurement loop overhead in a correct way, the loop check
* has been made a part of the benchmark. This does have
* an impact - though a very minor one - on the distribution
* statistics which have been updated for this version.
*
* All changes within the measurement loop are described
* and discussed in the companion paper "Rationale for
* Dhrystone version 2".
*
* Because of the self-imposed limitation that the order and
* distribution of the executed statements should not be
* changed, there are still cases where optimizing compilers
* may not generate code for some statements. To a certain
* degree, this is unavoidable for small synthetic benchmarks.
* Users of the benchmark are advised to check code listings
* whether code is generated for all statements of Dhrystone.
*
* Version 2.1 is identical to version 2.0 distributed via
* the UNIX network Usenet in March 1988 except that it corrects
* some minor deficiencies that were found by users of version 2.0.
* The only change within the measurement loop is that a
* non-executed "else" part was added to the "if" statement in
* Func3, and a non-executed "else" part removed from Proc3.
*
***************************************************************************
*
* Compilation model and measurement (IMPORTANT):
*
* This program contains the Dhrystone program, including measurement setup,
* in one file. The original (Ada) program contained three packages,
* - a package with global type definitions,
* - Pack_1, containing the main program (Proc_0 in Ada) and procedures
* Proc_1, ... , Proc_5,
* - Pack_2, containing Proc_6, ... , Proc_8, Func_1, ..., Func_3.
* Since ISO/ANSI Standard Pascal provides no means to express separate
* compilation (although many Pascal implementations provide such a feature),
* it is not possible to formulate a portable Pascal version with the program
* in several modules, corresponding more closely to the Ada and C versions.
* Therefore, no attempt has been made to construct a Pascal version with
* the program consisting of several modules.
*
* This difference may impact execution time because the compiler can
* perform more data flow analysis for a single-module program;
* sophisticated compilers may be able to suppress code generation for
* some parts of the program.
* Users should check machine code listings generated by the compiler
* to ensure that code is generated for all parts of the program.
*
* The following "ground rules" apply for measurements:
* - No procedure merging
* - Otherwise, compiler optimizations are allowed but should be indicated
* See the companion paper "Rationale for Dhrystone Version 2" for a more
* detailed discussion of these ground rules.
*
* For 16-Bit processors (e.g. 80x86), times for all compilation models
* ("small", "medium", "large") should be given if possible, together
* with a definition of these models for the compiler system used.
*
**************************************************************************
*
* Dhrystone (Pascal version) statistics:
*
* [Comment from the first distribution by Reinhold Weicker,
* the distribution statistics have been updated for Version 2.1.
* Note that because of language differences, the numbers are different
* from the Ada version. The main difference is that the variables that
* are local variables of "Proc_0" (Ada) or "main" (C) are global
* variables in the Pascal version.]
*
* The following program contains statements of a high level programming
* language (here: Pascal) in a distribution considered representative:
*
* assignments 58
* control statements 28
* procedure, function calls 15
*
* 100 statements are dynamically executed. The program is balanced with
* respect to the three aspects:
*
* - statement type
* - operand type (for simple data types)
* - operand access
* operand global, local, parameter, or constant.
* There is no static nesting of blocks or procedures,
* therefore all variables are either global or local.
*
* The combination of these three aspects is balanced only approximately.
*
* 1. Statement Type:
* ----------------- number
*
* V1 := V2 15
* V := Constant 12
* (incl. V1 := F(..)
* Assignment, 7
* with array element
* Assignment, 6
* with record component
* --
* 40 40
*
* X := Y +|-|and|or Z 5
* X := Y +|-|"=" Constant 6
* X := X +|- 1 3
* X := Y *|/ Z 2
* X := Expression, 1
* two operators
* X := Expression, 1
* three operators
* --
* 18 18
*
* if .... then .... 14
* with "else" 7
* without "else" 7
* executed 3
* not executed 4
* for I in 1..N do ... 7 | counted every time
* while ... do ... 4 | the loop condition
* repeat ... until 1 | is evaluated
* case ... end 1
* with 1
* --
* 28 28
*
* P (...) procedure call 10
* X := F (...)
* function call 5
* --
* 15 15
* ---
* 101
*
* 22 of the 58 assignments have a variable of a constrained
* (sub-)type as their destination. In general, discriminant checks
* will be necessary in these cases; however, the compiler may
* optimize out some of these checks.
*
* The average number of parameters in procedure or function calls
* is 1.80 (not counting the function values as implicit parameters).
*
*
* 2. Operators
* ------------
* number approximate
* percentage
*
* Arithmetic 27 52.9
*
* + 16 31.4
* - 7 13.7
* * 3 5.9
* div 1 2.0
*
* Comparison 20 39.2
*
* = 9 17.6
* <> 4 7.8
* > 1 2.0
* < 3 5.9
* >= 1 2.0
* <= 2 3.9
*
* Logic 4 7.8
*
* AND 1 2.0
* OR 1 2.0
* NOT 2 3.9
*
* -- -----
* 51 99.9
*
*
* 3. Operand Type (counted once per operand reference):
* ---------------
* number approximate
* percentage
*
* Integer 135 54.7 %
* Character 47 19.0 %
* Enumeration 31 12.6 %
* Boolean 13 5.3 %
* Pointer 11 4.5 %
* String30 6 2.4 %
* Array 2 0.8 %
* Record 2 0.8 %
* --- -------
* 247 100.1 %
*
* When there is an access path leading to the final operand (e.g. a record
* component), only the final data type on the access path is counted.
*
* There are 16 accesses to components of a record, 9 of them go to
* a component in a variant part. For some of these accesses, the
* compiler may suppress generation of code checking the tag field
* during optimization.
*
*
* 3. Operand Locality:
* -------------------
*
* local variable 84 34.0 %
* global variable 58 23.5 %
* parameter 45 18.2 %
* value 23 9.3 %
* reference 22 8.9 %
* function result 5 2.0 %
* constant 55 22.3 %
* --- -------
* 247 100.0 %
*
*
* The program does not compute anything meaningful, but it is syntactically
* and semantically correct. All variables have a value assigned to them
* before they are used as a source operand.
*
* There may be cases where a highly optimizing compiler may recognize
* unnecessary statements and may not generate code for them.
*
* There has been no explicit effort to account for the effects of a
* cache, or to balance the use of long or short displacements for code or
* data.
*
****************************************************************************
*)
const (* for measurement *)
MicrosecondsPerClock = 1000;
ClocksPerSecond = 1000;
(* In Berkeley UNIX Pascal, the function "clock" *)
(* returns milliseconds *)
TooSmallTime = 2000;
(* Measurements should last at least 2 seconds *)
type
(* Global type definitions *)
Enumeration = (Ident1, Ident2, Ident3, Ident4, Ident5);
OneToThirty = 1..30;
OneToFifty = 1..50;
CapitalLetter = 'A'..'Z';
String30 = STRING [30];
Array1DimInteger = array [OneToFifty] of integer;
Array2DimInteger = array [OneToFifty, OneToFifty] of integer;
RecordPointer = ^RecordType;
RecordType =
record
PointerComp: RecordPointer;
case Discr: Enumeration of
Ident1: (* only this variant is used, *)
(* but in some cases discriminant *)
(* checks are necessary *)
(EnumComp: Enumeration;
IntComp: OneToFifty;
StringComp: String30);
Ident2:
(Enum2Comp: Enumeration;
String2Comp: String30);
Ident3, Ident4, Ident5:
(Char1Comp,
Char2Comp: char);
end; (* record *)
var
(* Ada version: Variables local in Proc_0 *)
Int1Glob,
Int2Glob,
Int3Glob: OneToFifty;
CharIndex: char;
EnumGlob: Enumeration;
String1Glob,
String2Glob: String30;
(* Ada version: Variables global in Pack_1 *)
PointerGlob,
NextPointerGlob: RecordPointer;
IntGlob: integer;
BoolGlob: boolean;
Char1Glob,
Char2Glob: char;
Array1Glob: Array1DimInteger;
Array2Glob: Array2DimInteger;
(* Variables for measurement *)
RunIndex,
NumberOfRuns: integer;
BeginClock,
EndClock,
SumClocks: longint;
Microseconds,
DhrystonesPerSecond: real;
I: integer;
(* end of variables for measurement *)
procedure Proc1 ( PointerParVal: RecordPointer); forward;
procedure Proc2 (var IntParRef: OneToFifty); forward;
procedure Proc3 (var PointerParRef: RecordPointer); forward;
procedure Proc4; forward;
(* without parameters *)
procedure Proc5; forward;
(* without parameters *)
procedure Proc6 ( EnumParVal: Enumeration;
var EnumParRef: Enumeration); forward;
procedure Proc7 ( Int1ParVal,
Int2ParVal: OneToFifty;
var IntParRef: OneToFifty); forward;
procedure Proc8 (var Array1ParRef: Array1DimInteger;
var Array2ParRef: Array2DimInteger;
Int1ParVal,
Int2ParVal: integer); forward;
function Func1 ( Char1ParVal,
Char2ParVal: CapitalLetter):
Enumeration; forward;
function Func2 (var String1ParRef,
String2ParRef: String30):
boolean; forward;
function Func3 ( EnumParVal: Enumeration):
boolean; forward;
procedure Proc1; (* (PointerParVal: RecordPointer) *)
(* executed once *)
begin
with PointerParVal^.PointerComp^ (* = PointerGlobNext *) do
begin
PointerParVal^.PointerComp^ := PointerGlob^;
PointerParVal^.IntComp := 5;
IntComp := PointerParVal^.IntComp;
PointerComp := PointerParVal^.PointerComp;
Proc3 (PointerComp);
(* PointerParVal^.PointerComp^.PointerComp = PointerGlob^.PointerComp *)
if Discr = Ident1
then (* executed *)
begin
IntComp := 6;
Proc6 (PointerParVal^.EnumComp, EnumComp);
PointerComp := PointerGlob^.PointerComp;
Proc7 (IntComp, 10, IntComp);
end (* then *)
else (* not executed *)
PointerParVal^ := PointerParVal^.PointerComp^;
end; (* with *)
end; (* Proc1 *)
procedure Proc2; (* (var IntParRef: OneToFifty) *)
(* executed once *)
(* InParRef = 3, becomes 7 *)
var
IntLoc: OneToFifty;
EnumLoc: Enumeration;
begin
IntLoc := IntParRef + 10;
repeat (* executed once *)
if Char1Glob = 'A'
then (* executed *)
begin
Dec (IntLoc);
IntParRef := IntLoc - IntGlob;
EnumLoc := Ident1;
end (* if *)
until EnumLoc = Ident1; (* true *)
end; (* Proc2 *)
procedure Proc3; (* (var PointerParRef: RecordPointer) *)
(* executed once *)
(* PointerParRef becomes PointerGlob *)
begin
if PointerGlob <> nil
then (* executed *)
PointerParRef := PointerGlob^.PointerComp;
Proc7 (10, IntGlob, PointerGlob^.IntComp);
end; (* Proc3 *)
procedure Proc4; (* without parameters *)
(* executed once *)
var
BoolLoc: boolean;
begin
BoolLoc := Char1Glob = 'A';
BoolGlob := BoolLoc or BoolGlob;
Char2Glob := 'B';
end; (* Proc4 *)
procedure Proc5; (* without parameters *)
(* executed once *)
begin
Char1Glob := 'A';
BoolGlob := false;
end; (* Proc5 *)
procedure Proc6; (* ( EnumParVal: Enumeration;
var EnumParRef: Enumeration) *)
(* executed once *)
(* EnumParVal = Ident3, EnumParRef becomes Ident2 *)
begin
EnumParRef := EnumParVal;
if not Func3 (EnumParVal)
then (* not executed *)
EnumParRef := Ident4;
case EnumParVal of
Ident1: EnumParRef := Ident1;
Ident2: if IntGlob > 100
then EnumParRef := Ident1
else EnumParRef := Ident4;
Ident3: EnumParRef := Ident2; (* executed *)
Ident4: ;
Ident5: EnumParRef := Ident3;
end; (* case *)
end; (* Proc6 *)
procedure Proc7; (* ( Int1ParVal,
Int2ParVal: OneToFifty;
var IntParRef: OneToFifty) *)
(* executed three times *)
(* first call: Int1ParVal = 2, Int2ParVal = 3, *)
(* IntParRef becomes 7 *)
(* second call: Int1ParVal = 10, Int2ParVal = 5, *)
(* IntParRef becomes 17 *)
(* third call: Int1ParVal = 6, Int2ParVal = 10, *)
(* IntParRef becomes 18 *)
var
IntLoc: OneToFifty;
begin
IntLoc := Int1ParVal + 2;
IntParRef := Int2ParVal + IntLoc;
end; (* Proc7 *)
procedure Proc8; (* (var Array1ParRef: Array1DimInteger;
var Array2ParRef: Array2DimInteger;
Int1ParVal,
Int2ParVal: integer) *)
(* executed once *)
(* Int1ParVal = 3 *)
(* Int2ParVal = 7 *)
var
IntIndex,
IntLoc: OneToFifty;
begin
IntLoc := Int1ParVal + 5;
Array1ParRef [IntLoc] := Int2ParVal;
Array1ParRef [IntLoc+1] := Array1ParRef [IntLoc];
Array1ParRef [IntLoc+30] := IntLoc;
for IntIndex := IntLoc to IntLoc+1 do
Array2ParRef [IntLoc, IntIndex] := IntLoc;
Array2ParRef [IntLoc, IntLoc-1] := Array2ParRef [IntLoc, IntLoc-1] + 1;
Array2ParRef [IntLoc+20, IntLoc] := Array1ParRef [IntLoc];
IntGlob := 5;
end; (* Proc8 *)
function Func1; (* (Char1ParVal,
Char2ParVal: CapitalLetter): Enumeration *)
(* executed three times, returns always Ident1 *)
(* first call: Char1ParVal = 'H', Char2ParVal = 'R' *)
(* second call: Char1ParVal = 'A', Char2ParVal = 'C' *)
(* third call: Char1ParVal = 'B', Char2ParVal = 'C' *)
var
Char1Loc, Char2Loc: CapitalLetter;
begin
Char1Loc := Char1ParVal;
Char2Loc := Char1Loc;
if Char2Loc <> Char2ParVal
then (* executed *)
Func1 := Ident1
else (* not executed *)
begin
Char1Glob := Char1Loc;
Func1 := Ident2;
end;
end; (* Func1 *)
function Func2; (* (var String1ParRef,
String2ParRef: String30): boolean *)
(* executed once, returns false *)
(* String1ParRef = 'DHRYSTONE PROGRAM, 1''ST STRING' *)
(* String2ParRef = 'DHRYSTONE PROGRAM, 2''ND STRING' *)
var
IntLoc: OneToThirty;
CharLoc: CapitalLetter;
begin
IntLoc := 2;
while IntLoc <= 2 do (* loop body executed once *)
if Func1 (String1ParRef[IntLoc],
String2ParRef[IntLoc+1]) = Ident1
then (* executed *)
begin
CharLoc := 'A';
Inc (IntLoc);
end; (* if, while *)
if (CharLoc >= 'W') and (CharLoc < 'Z')
then (* not executed *)
IntLoc := 7;
if CharLoc = 'R'
then (* not executed *)
Func2 := true
else (* executed *)
begin
if String1ParRef > String2ParRef
then (* not executed *)
begin
IntLoc := IntLoc + 7;
IntGlob := IntLoc;
Func2 := true
end
else (* executed *)
Func2 := false;
end; (* if CharLoc *)
end; (* Func2 *)
function Func3; (* (EnumParVal: Enumeration): boolean *)
(* executed once, returns true *)
(* EnumParVal = Ident3 *)
var
EnumLoc: Enumeration;
begin
EnumLoc := EnumParVal;
if EnumLoc = Ident3
then (* executed *)
Func3 := true
else (* not executed *)
Func3 := false;
end; (* Func3 *)
FUNCTION Dhrystones (Index: DOUBLE): DOUBLE;
begin (* main program, corresponds to procedures *)
(* Main and Proc_0 in the Ada version *)
(* Initializations *)
new (NextPointerGlob);
new (PointerGlob);
PointerGlob^.PointerComp := NextPointerGlob;
PointerGlob^.Discr := Ident1;
PointerGlob^.EnumComp := Ident3;
PointerGlob^.IntComp := 40;
PointerGlob^.StringComp := 'DHRYSTONE PROGRAM, SOME STRING';
String1Glob := 'DHRYSTONE PROGRAM, 1''ST STRING';
Array2Glob [8,7] := 10;
NumberofRuns := Round (200 * (Index / 3 + 1));
BeginClock := Clock;
(***************)
(* Start timer *)
(***************)
for RunIndex := 1 to NumberOfRuns do
begin
Proc5;
Proc4;
(* Char1Glob = 'A', Char2Glob = 'B', BoolGlob = false *)
Int1Glob := 2;
Int2Glob := 3;
String2Glob := 'DHRYSTONE PROGRAM, 2''ND STRING';
EnumGlob := Ident2;
BoolGlob := not Func2 (String1Glob, String2Glob);
(* BoolGlob = true *)
while Int1Glob < Int2Glob do (* loop body executed once *)
begin
Int3Glob := 5 * Int1Glob - Int2Glob;
(* Int3Glob = 7 *)
Proc7 (Int1Glob, Int2Glob, Int3Glob);
(* Int3Glob = 7 *)
Inc (Int1Glob);
end; (* while *)
(* Int1Glob = 3 *)
Proc8 (Array1Glob, Array2Glob, Int1Glob, Int3Glob);
(* IntGlob = 5 *)
Proc1 (PointerGlob);
for CharIndex := 'A' to Char2Glob do (* loop body executed twice *)
if EnumGlob = Func1 (CharIndex, 'C')
then (* not executed *)
begin
Proc6 (Ident1, EnumGlob);
String2Glob := 'DHRYSTONE PROGRAM, 3''RD STRING';
Int2Glob := RunIndex;
IntGlob := RunIndex;
end;
(* Int1Glob = 3, Int2Glob = 3, Int3Glob = 7 *)
Int2Glob := Int2Glob * Int1Glob;
Int1Glob := Int2Glob div Int3Glob;
Int2Glob := 7 * (Int2Glob - Int3Glob) - Int1Glob;
(* Int1Glob = 1, Int2Glob = 13, Int3Glob = 7 *)
Proc2 (Int1Glob);
(* Int1Glob = 5 *)
end; (* for RunIndex *)
EndClock := Clock;
(**************)
(* Stop timer *)
(**************)
SumClocks := EndClock - BeginClock;
Dhrystones := NumberOfRuns * (ClocksPerSecond / SumClocks);
end;
end.